const crypto=require('crypto');
const router=require('koa-router')();
const koaBody=require('koa-body');
const events=require('events');
const config=require('../config/config');
const {User,App,Auth}=require('../models/index');
const authRedis=require('../models/auth.redis.server.model');

//申请授权view
router.get('/',async ctx=>{
    let {client_id}=ctx.query;
    let app=await App.findOne({client_id},{name:true});

    await ctx.render('oauth',{
        title:'申请授权',
        app,
        success:ctx.flash.success,
        error:ctx.flash.error
    });
});
//确认申请授权
router.post('/',koaBody(),async ctx=>{
    let {client_id,response_type,callback,scope,state}=ctx.query,{body}=ctx.request,ee=new events();
    ee.on('fail',msg=>{
        ctx.flash={error:msg};
        ctx.redirect('back');
    });


    if(!client_id)return ee.emit('fail','client_id错误');
    if('code'!==response_type)return ee.emit('fail',`申请的授权方式不支持,请使用"code"方式`);
    if(!callback)return ee.emit('fail',`回调地址错误`);
    if(!scope || !config.auth.scopes.find(scope=>scope==scope))return ee.emit('fail',`申请的授权范围错误`);

    let [user,app]=await Promise.all([
        User.findOne({name:body.name},{_id:true,name:true,password:true}),
        App.findOne({client_id})
    ]);
    if(!user || crypto.createHash('md5').update(body.password).digest('hex')!==user.password)return ee.emit('fail','用户名或密码错误');
    if(!app)return ee.emit('fail','应用不存在');

    let code=crypto.createHash('md5').update([client_id,user._id,Date.now(),Math.random(),config.secret].join()).digest('hex');
    await Promise.all([
        Auth.findOneAndUpdate({client_id,user:user._id},{//code
            type:'code',
            code,
            scope,
            time:new Date()
        },{upsert:true}),
        authRedis.addCode({client_id,code})
    ]);
    ctx.status=301;
    callback+=(callback.includes('?')?'&':'?')+'code='+code+(state?'&state='+state:'');
    ctx.redirect(callback);
});


//授权
router.get('/token',async ctx=>{
    let {query}=ctx,fields=['grant_type','client_id','code','callback','scope'],ee=new events();
    ee.on('fail',msg=>{
        console.log('Get token 参数错误：',msg);
        ctx.body={
            error:msg
        };
    });

    for(let field of fields){
        if(!query[field])return ee.emit('fail',`${field}参数不存在`);
    }

    if('authorization_code' !== query['grant_type'])return ee.emit('fail','grant_type参数错误');

    if(!config.auth.scopes.find(scope=>query.scope==scope))return ee.emit('fail','scope参数错误');

    let {client_id,code}=query;
    let [cacheCode,auth]=await Promise.all([
        authRedis.findCode({client_id,code}),
        Auth.findOne({client_id,code})
    ]);
    if(!cacheCode){
        await Auth.remove({client_id,code});
        return ee.emit('fail','授权码错误或已过期，请重新申请');
    }

    let token=crypto.createHash('md5').update([client_id,code,Date.now(),Math.random(),config.secret].join()).digest('hex');
    let refresh_token=crypto.createHash('md5').update([client_id,code,token,Date.now(),Math.random(),config.secret].join()).digest('hex');
    let ret=await Promise.all([
        authRedis.delCode({client_id,code}),
        authRedis.addToken({client_id,token}),
        Auth.update({client_id,code},{token,refresh_token}),
        App.update({client_id},{$addToSet:{users:auth.user}})
    ]);

    ctx.set('Cache-Control', 'no-cache');
    ctx.set('Content-Type', 'application/json;charset=UTF-8');
    ctx.body={
        access_token:token,
        token_type:"bearer",
        expires_in:config.auth.token,
        refresh_token,
        scope:query.scope
    };
});
router.get('/refresh',async ctx=>{
    let {query}=ctx,fields=['client_id','refresh_token','grant_type','scope'],ee=new events();
    ee.on('fail',msg=>{
        ctx.body={
            error:msg
        };
    });

    for(let field of fields){
        if(!query[field])return ee.emit('fail',`${field}参数不存在`);
    }

    if('authorization_code' !== query['grant_type'])return ee.emit('fail','grant_type参数错误');

    if(!config.auth.scopes.find(scope=>query.scope==scope))return ee.emit('fail','scope参数错误');

    let {client_id,refresh_token}=query;
    let tokenRet=await Auth.findOne({client_id,refresh_token});
    if(!tokenRet)return ee.emit('fail','client_id或refresh_token错误');

    let cacheToken=await authRedis.findToken({client_id,token:tokenRet.token});
    if(cacheToken)return ee.emit('fail','Token未过期，无需刷新');

    let token=crypto.createHash('md5').update([client_id,tokenRet.code,Date.now(),Math.random(),config.secret].join()).digest('hex');
    refresh_token=crypto.createHash('md5').update([client_id,tokenRet.code,token,Date.now(),Math.random(),config.secret].join()).digest('hex');

    await Promise.all([
        authRedis.addToken({client_id,token}),
        Auth.update({client_id,user:tokenRet.user},{token,refresh_token,time:new Date})
    ]);

    ctx.body={
        access_token:token,
        token_type:"bearer",
        expires_in:config.auth.token,
        refresh_token,
        scope:query.scope
    };
});
module.exports=router;